{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Paddle Quantum Quick Start Manual\n",
    "\n",
    "<em> Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved. </em>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "# Overview\n",
    "\n",
    "Quantum computing (QC) is a new computing model laying in the intersection of quantum mechanics and theory of computation. QC follows the fundamental laws of quantum theory to manipulate quantum bits (qubits). For many specific computational tasks, it is widely believed that quantum algorithms exhibit advantages over classical algorithms at least in theory. For a systematic introduction to the subject of QC, we refer to [1-2].\n",
    "\n",
    "In recent years, one of the popular research topics in QC is combining the potential of quantum computing and artificial intelligence. Quantum machine learning (QML) is such an interdisciplinary subject. Researchers want to utilize the information processing advantages of quantum computing to promote the development of artificial intelligence. On the other side, it is also worth exploring the possibility of using artificial intelligence technology to break through the bottleneck of quantum computing research and development. For introductory materials about quantum machine learning, please refer to [3-5].\n",
    "\n",
    "Here, we provide a quick start for users to get started with Paddle Quantum. Currently, you can read all the content online or download the Jupyter Notebook from our [GitHub](https://github.com/PaddlePaddle/Quantum/tree/master/introduction). In terms of content, the quick start includes the following sections:\n",
    "\n",
    "- Introduction to quantum computing and quantum neural network (QNN)\n",
    "- Introduction to Paddle Quantum\n",
    "- PaddlePaddle optimizer tutorial\n",
    "- A case study on quantum machine learning - Variational Quantum Eigensolver (VQE)\n",
    "\n",
    "**Latest version updated on:** Mar. 2nd, 2021 by Paddle Quantum developers.\n",
    "\n",
    "---\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Quantum Computing Fundamentals\n",
    "\n",
    "Quantum Computing (QC) uses unique phenomena in quantum physics (quantum superposition, quantum interference, and quantum entanglement) to design algorithms and help solve specific tasks in physics, chemistry, and optimization theory. There are several existing quantum computation models including the Adiabatic Quantum Computation (AQC) based on the adiabatic theorem and Measurement-Based Quantum Computation (MBQC). This introduction will focus on the most widely used Quantum Circuit model. In quantum circuits, the basic computation unit is the quantum bit (qubit)， which is similar to the concept of bit in classical computers. Classical bits can only be in one of the two states, 0 or 1. By comparison, qubits can not only be in states $|0\\rangle$ and $|1\\rangle$ but also in a superposition state (we will explain this concept later). Quantum circuit model utilize quantum logic gates to manipulate the states of these qubits. The mathematics behind this process is linear algebra in the complex domain. Here we assume the readers are already familiar with linear algebra."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## What is a qubit?\n",
    "\n",
    "### Mathematical representation\n",
    "\n",
    "In quantum mechanics, the state of a two-level quantum system (e.g. electron spin) can be expressed as a state vector obtained through linear combinations of the following orthonormal basis,\n",
    "\n",
    "$$\n",
    "|0\\rangle := \\begin{bmatrix} 1 \\\\ 0 \\end{bmatrix}, \\quad |1\\rangle := \\begin{bmatrix} 0 \\\\ 1 \\end{bmatrix}.\n",
    "\\tag{1}\n",
    "$$\n",
    "\n",
    "The vector representation here follows the Dirac notation (bra-ket) in quantum physics. This orthonormal basis $\\{|0\\rangle, |1\\rangle \\}$ is known as the **computational basis**. Physically, one could consider $|0\\rangle$ and $|1\\rangle$ as the energy ground state and excited state of an atom, respectively. All possible pure states of a qubit can be regarded as normalized vectors in the two-dimensional Hilbert space. Moreover, multi-qubit states can be represented by unit vectors in high-dimensional Hilbert space where the basis is the tensor product of  $\\{|0\\rangle, |1\\rangle\\}$. For example, a 2-qubit quantum state can be represented by a unit complex vector in a 4-dimensional Hilbert space with the orthonormal basis,\n",
    "\n",
    "$$\n",
    "\\left\\{\n",
    "|00\\rangle = |0\\rangle\\otimes |0\\rangle := \\begin{bmatrix} 1 \\\\ 0 \\\\ 0 \\\\ 0 \\end{bmatrix}, \\quad \n",
    "|01\\rangle = |0\\rangle\\otimes |1\\rangle := \\begin{bmatrix} 0 \\\\ 1 \\\\ 0 \\\\ 0 \\end{bmatrix}, \\quad\n",
    "|10\\rangle = |1\\rangle\\otimes |0\\rangle := \\begin{bmatrix} 0 \\\\ 0 \\\\ 1 \\\\ 0 \\end{bmatrix}, \\quad\n",
    "|11\\rangle = |1\\rangle\\otimes |0\\rangle := \\begin{bmatrix} 0 \\\\ 0 \\\\ 0 \\\\ 1 \\end{bmatrix}\n",
    "\\right\\}.\n",
    "\\tag{2}\n",
    "$$\n",
    "\n",
    "By convention, the leftmost position in ket notation represents the first qubit $q_0$, the second position represents the second qubit $q_1$, and so on. The symbol $\\otimes$ denotes the tensor product operation. It works as follows: Given two matrices $A_{m\\times n}$ and $B_{p \\times q}$, then the tensor product of $A, B$ is\n",
    "\n",
    "$$\n",
    "A \\otimes B =\n",
    "\\begin{bmatrix}\n",
    "a_{11}B & \\cdots & a_{1 n}B\\\\\n",
    "\\vdots & \\ddots & \\vdots \\\\\n",
    "a_{m1}B & \\cdots & a_{m n}B\n",
    "\\end{bmatrix}_{(mp)\\times (nq)}.\n",
    "\\tag{3}\n",
    "$$\n",
    "\n",
    "Any single qubit quantum state $|\\psi\\rangle$ can be written as a linear combination (superposition) of the basis vectors $|0\\rangle$ and $|1\\rangle$. \n",
    "\n",
    "$$\n",
    "|\\psi\\rangle = \\alpha |0\\rangle + \\beta |1\\rangle\n",
    ":= \\begin{bmatrix} \\alpha \\\\ \\beta \\end{bmatrix}.\n",
    "\\tag{4}\n",
    "$$\n",
    "\n",
    "where $\\alpha$ and $\\beta$ are **complex numbers** referred as the probability amplitudes. According to Born Rule, the probability to find the qubit in $|0\\rangle$ state is $|\\alpha|^2$; and the probability of $|1\\rangle$ is $|\\beta|^2$. Since the sum of probabilities equals to 1, one should introduce the constraint: $|\\alpha|^2 + |\\beta|^2 = 1$.\n",
    "\n",
    "\n",
    "### Bloch sphere representation\n",
    "\n",
    "Geometrically, one can use a point on the unit sphere to represent the pure quantum state of a qubit. This sphere is called the **Bloch sphere**, (see Figure 1)\n",
    "\n",
    "$$\n",
    "|\\psi\\rangle = \\alpha |0\\rangle + \\beta |1\\rangle\n",
    "= \\cos\\bigg(\\frac{\\theta}{2}\\bigg) |0\\rangle + e^{i\\varphi}\\sin\\bigg(\\frac{\\theta}{2}\\bigg) |1\\rangle.\n",
    "\\tag{5}\n",
    "$$\n",
    "\n",
    "**Note**: The states of multi-qubit quantum systems cannot be directly represented by Bloch spheres. For a classical bit in state 0 or 1, it corresponds to the north or south pole of the Bloch sphere. **A qubit state can be at any point on the sphere. Such a superposition state is impossible for classical bits**. For example, the quantum state $\\frac{1}{\\sqrt{2}}\\big(|0\\rangle + i|1\\rangle\\big)$ is at the intersection of the equator and $+y$ axis.\n",
    "\n",
    "![intro-fig-bloch](./figures/intro-fig-bloch.png \"**Figure 1.** Bloch sphere representation of a single qubit. [[Image source]](https://en.wikipedia.org/wiki/Qubit)\")\n",
    "\n",
    "The following content is for readers who are more familiar with quantum computing. If you find it difficult to follow, don’t worry, you can skip it. Due to the interaction between qubits and decoherence, for a system with multiple qubits, its single-qubit subsystem will no longer stay in pure states, but a mixed state in general. The concept of mixed state can be regarded as a statistical mixture of multiple pure states. **The single-bit mixed state can be seen as a point inside the Bloch sphere**. The mixed state needs to be described in the density matrix formulation of quantum mechanics, for example the following mixed state has $1/2$ probability to be in $|0\\rangle$ or $|1\\rangle$,\n",
    "\n",
    "$$\n",
    "\\rho_{\\text{mixed}} = \\sum_i P_i |\\psi_i\\rangle\\langle\\psi_i| = \\frac{1}{2} |0\\rangle\\langle0| + \\frac{1}{2} |1\\rangle\\langle1| := \\frac{1}{2}  \\begin{bmatrix} 1 \\\\ 0\\end{bmatrix} \\begin{bmatrix} 1 & 0 \\end{bmatrix} +  \\frac{1}{2}  \\begin{bmatrix} 0 \\\\ 1\\end{bmatrix} \\begin{bmatrix} 0 & 1 \\end{bmatrix} = \\frac{1}{2} \\begin{bmatrix} 1 & 0\\\\ 0 & 1 \\end{bmatrix}.\n",
    "\\tag{6}\n",
    "$$\n",
    "\n",
    "The row vector (bra) $\\langle0| = |0\\rangle^\\dagger$ is the conjugate transpose of the column vector (ket) $|0\\rangle$.\n",
    "\n",
    "**Note:** For more information, please refer to [Wikipedia](https://en.wikipedia.org/wiki/Qubit)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## What is a quantum logic gate?\n",
    "\n",
    "In classical computers, we can apply basic logical operations (NOT gates, NAND gates, XOR gates, AND gates, and OR gates) on classical bits and combine them into more complicated operations. Quantum computing has a completely different set of logical operations, which are called quantum gates. We cannot compile existing C++ programs on a quantum computer. Because **classical computers and quantum computers have different logic gate structures, quantum algorithms need to be constructed using quantum gates**. Mathematically, a quantum gates can be expressed as a unitary matrix. Unitary operations could preserve vector length, which is a desirable property. Otherwise, if we operate on a pure state, it will be degraded into a mixed state, making it unreliable for the following running time. The unitary matrix is defined as:\n",
    "\n",
    "$$\n",
    "U^{\\dagger}U = UU^{\\dagger} = I,\n",
    "\\quad \\text{and} \\quad\n",
    "\\Vert |\\psi\\rangle \\Vert = \\Vert U|\\psi\\rangle\\Vert = 1.\n",
    "\\tag{7}\n",
    "$$\n",
    "\n",
    "where $U^{\\dagger}$ is the conjugate transpose of $U$, and $I$ represents the identity matrix. But what is the physical meaning of representing quantum gates as unitary matrices? This implies that all quantum gates must be reversible. For any gate logic $U$, one can always find the corresponding reverse operation $U^\\dagger$. In addition, the unitary matrix must be a square matrix, because the input and output of the quantum operation require the same number of qubits. A quantum gate acting on $n$ qubits can be written as a $2^n \\times 2^n$ unitary matrix. The most common quantum gates act on one or two qubits, just like classical logic gates.\n",
    "\n",
    "### Single-qubit gate\n",
    "\n",
    "Next, we introduce single-qubit gates in quantum computing, including the Pauli matrices $\\{X, Y, Z\\}$, single-bit rotation gates $\\{R_x, R_y, R_z\\}$ and the Hadamard gate $H$. Firstly, **NOT gate** is important for both classical and quantum computing,\n",
    "\n",
    "$$\n",
    "X := \\begin{bmatrix} 0 &1 \\\\ 1 &0 \\end{bmatrix}.\n",
    "\\tag{8}\n",
    "$$\n",
    "\n",
    "This quantum gate (unitary matrix) acts on the state of a single qubit (a complex vector). The operation is essentially **multiplication between a matrix and a column vector**:\n",
    "\n",
    "$$\n",
    "X |0\\rangle := \\begin{bmatrix} 0 &1 \\\\ 1 &0 \\end{bmatrix} \\begin{bmatrix} 1 \\\\0 \\end{bmatrix}\n",
    "=\\begin{bmatrix} 0 \\\\1 \\end{bmatrix} = |1\\rangle,\n",
    "\\quad \\text{and} \\quad\n",
    "X |1\\rangle := \\begin{bmatrix} 0 &1 \\\\ 1 &0 \\end{bmatrix} \\begin{bmatrix} 0 \\\\1 \\end{bmatrix}\n",
    "=\\begin{bmatrix} 1 \\\\0 \\end{bmatrix}=|0\\rangle.\n",
    "\\tag{9}\n",
    "$$\n",
    "\n",
    "Recall the Bloch sphere representation, this operation $X$ acting on a qubit state (a point on the Bloch sphere) is equivalent to **a rotation about the $x$ axis in the Bloch sphere with angle $\\pi$** . This is why $X$ can be expressed as $R_x(\\pi)$ (differ by a global phase $e^{-i\\pi/2} = -i$ ). The other two Pauli matrices $Y$ and $Z$ are very similar in this sense (representing rotation around the $y$ and $z$ axes with angle $\\pi$):\n",
    "\n",
    "$$\n",
    "Y := \\begin{bmatrix} 0 &-i \\\\ i &0 \\end{bmatrix},\n",
    "\\quad \\text{and} \\quad \n",
    "Z := \\begin{bmatrix} 1 &0 \\\\ 0 &-1 \\end{bmatrix}.\n",
    "\\tag{10}\n",
    "$$\n",
    "\n",
    "Generally speaking, any quantum gate that rotates $\\theta$ on the corresponding axis on the Bloch sphere can be expressed as\n",
    "\n",
    "$$\n",
    "R_x(\\theta) := \n",
    "\\begin{bmatrix} \n",
    "\\cos \\frac{\\theta}{2} &-i\\sin \\frac{\\theta}{2} \\\\ \n",
    "-i\\sin \\frac{\\theta}{2} &\\cos \\frac{\\theta}{2} \n",
    "\\end{bmatrix}\n",
    ",\\quad \n",
    "R_y(\\theta) := \n",
    "\\begin{bmatrix}\n",
    "\\cos \\frac{\\theta}{2} &-\\sin \\frac{\\theta}{2} \\\\ \n",
    "\\sin \\frac{\\theta}{2} &\\cos \\frac{\\theta}{2} \n",
    "\\end{bmatrix}\n",
    ",\\quad \n",
    "R_z(\\theta) := \n",
    "\\begin{bmatrix}\n",
    "e^{-i\\frac{\\theta}{2}} & 0 \\\\ \n",
    "0 & e^{i\\frac{\\theta}{2}}\n",
    "\\end{bmatrix}.\n",
    "\\tag{11}\n",
    "$$\n",
    "\n",
    "In addition to the rotation gates, the most important single-qubit gate is the Hadamard gate. The corresponding Bloch spherical interpretation consists of two separate rotations, first rotating $\\pi$ around the $z$-axis, and then rotating $\\pi/2$ around the $y$-axis. Its matrix representation is\n",
    "\n",
    "$$\n",
    "H := \\frac{1}{\\sqrt{2}}\\begin{bmatrix} 1 &1 \\\\ 1 &-1 \\end{bmatrix}.\n",
    "\\tag{12}\n",
    "$$\n",
    "\n",
    "### Two-bit quantum gate\n",
    "\n",
    "We can expand the idea of single-qubit gates to multi-qubit. There are two ways to realize this expansion. The first is to apply single-qubit gates on selected qubits, while the other qubits are not operated. The figure below gives a concrete example:\n",
    "\n",
    "![intro-fig-hadamard](./figures/intro-fig-hadamard.png \"**Figure 2.** Circuit representation and interpretation of two-qubit logic operations. [[Image source]](https://en.wikipedia.org/wiki/Quantum_logic_gate)\")\n",
    "\n",
    "The quantum gate acting on two-qubit system can be expressed as a $4\\times4$ unitary matrix\n",
    "\n",
    "$$\n",
    "U = H \\otimes I \n",
    "= \\frac{1}{\\sqrt{2}} \\begin{bmatrix} 1 &1 \\\\ 1 &-1 \\end{bmatrix} \n",
    "\\otimes \\begin{bmatrix} 1 &0 \\\\ 0 &1 \\end{bmatrix} \n",
    "= \\frac{1}{\\sqrt{2}} \\,\n",
    "\\begin{bmatrix}\n",
    "1 &0 &1 &0  \\\\ \n",
    "0 &1 &0 &1  \\\\\n",
    "1 &0 &-1 &0 \\\\\n",
    "0 &1 &0 &-1 \n",
    "\\end{bmatrix}.\n",
    "\\tag{13}\n",
    "$$\n",
    "\n",
    "Another way is to apply two-qubit gates directly. For example, $\\text{CNOT}$  gate will make the state of one qubit affect another qubit state.\n",
    "\n",
    "$$\n",
    "\\text{CNOT} :=\n",
    "\\begin{bmatrix}\n",
    "1 &0 &0 &0 \\\\\n",
    "0 &1 &0 &0 \\\\\n",
    "0 &0 &0 &1 \\\\\n",
    "0 &0 &1 &0\n",
    "\\end{bmatrix},\n",
    "\\tag{14}\n",
    "$$\n",
    "\n",
    "When $\\text{CNOT}$  acts on the computational basis, we have\n",
    "\n",
    "$$\n",
    "\\text{CNOT} |00\\rangle = |00\\rangle, \\quad\n",
    "\\text{CNOT} |01\\rangle = |01\\rangle, \\quad\n",
    "\\text{CNOT} |10\\rangle = |11\\rangle, \\quad\n",
    "\\text{CNOT} |11\\rangle = |10\\rangle.\n",
    "\\tag{15}\n",
    "$$\n",
    "\n",
    "We can conclude that when the first qubit is in the $|1\\rangle$ state, $\\text{CNOT}$ will act $X$ gate on the second qubit. If the first qubit is in the $|0\\rangle$ state, then the second qubit is not affected in any way. This is why $\\text{CNOT}$ stands for the controlled-$\\text{NOT}$ gate. The following list contains frequently used quantum gates and their matrix representations. **All of these quantum gates can be called in Paddle Quantum**.\n",
    "\n",
    "![intro-fig-gates](./figures/intro-fig-gates.png \"**Figure 3.** List of common quantum gates. [[Image source]](https://en.wikipedia.org/wiki/Quantum_logic_gate)\")\n",
    "\n",
    "**Note**: For more information, please see the following Wikipedia [link](https://en.wikipedia.org/wiki/Quantum_logic_gate)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## What is measurement in quantum mechanics?\n",
    "\n",
    "For a two-level quantum system, such as the spin of an electron, it can be spin up $\\uparrow$ or spin down $\\downarrow$, corresponding to state $|0\\rangle$ and state $|1\\rangle$. As mentioned before, the electron can be in a superposition state of spin up and down, which is $|\\psi\\rangle =\\alpha |0\\rangle + \\beta |1\\rangle$. The measurement will help us further understand what is a superposition state. It is worth noting that the measurement in quantum mechanics usually refers to a statistical result rather than a single measurement. This is due to the nature of measurements in quantum physics, which collapses the observed quantum state. For example, if we measure an electron in state $|\\psi\\rangle =\\alpha |0\\rangle + \\beta |1\\rangle$, we will have a probability of $|\\alpha|^2$ to obtain the measurement results of spin up, and after measurement, the quantum state collapses to the post-measurement state $ |0\\rangle$. Similarly, we also have a probability of $|\\beta|^2$ to get the spin down post-measurement state $|1\\rangle$. So if we want to get the value of $\\alpha$ accurately, one experiment is obviously not enough. We need to prepare a lot of electrons in the superposition state $\\alpha |0\\rangle + \\beta |1\\rangle$, measure the spin of each electron, and then count the frequency. Measurement has a special place in quantum mechanics. If the reader finds it difficult to understand, we refer to [Measurement in Quantum Mechanics](https://en.wikipedia.org/wiki/Measurement_in_quantum_mechanics) for more information."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example and exercise\n",
    "\n",
    "### Example: Using Paddle Quantum to create a $X$ gate\n",
    "\n",
    "**Note:** All single-bit rotation gates are established as follows:\n",
    "\n",
    "$$\n",
    "R_x(\\theta) :=\n",
    "\\begin{bmatrix}\n",
    "\\cos \\frac{\\theta}{2} &-i\\sin \\frac{\\theta}{2} \\\\\n",
    "-i\\sin \\frac{\\theta}{2} &\\cos \\frac{\\theta}{2}\n",
    "\\end{bmatrix}\n",
    ",\\quad\n",
    "R_y(\\theta) :=\n",
    "\\begin{bmatrix}\n",
    "\\cos \\frac{\\theta}{2} &-\\sin \\frac{\\theta}{2} \\\\\n",
    "\\sin \\frac{\\theta}{2} &\\cos \\frac{\\theta}{2}\n",
    "\\end{bmatrix}\n",
    ",\\quad\n",
    "R_z(\\theta) :=\n",
    "\\begin{bmatrix}\n",
    "e^{-i\\frac{\\theta}{2}} & 0 \\\\\n",
    "0 & e^{i\\frac{\\theta}{2}}\n",
    "\\end{bmatrix}.\n",
    "\\tag{16}\n",
    "$$\n",
    "\n",
    "Therefore, it is not difficult to see that the $X$ gate can be expressed as $R_x(\\pi)$. The following code will generate the $X$ gate:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-04-30T09:20:08.888161Z",
     "start_time": "2021-04-30T09:20:05.709738Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The matrix representation of quantum gate is:\n",
      "[[ 6.123234e-17+0.j -6.123234e-17-1.j]\n",
      " [ 6.123234e-17-1.j  6.123234e-17+0.j]]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import paddle\n",
    "from paddle_quantum.circuit import UAnsatz\n",
    "from paddle_quantum.utils import dagger, random_pauli_str_generator, pauli_str_to_matrix\n",
    "from paddle_quantum.state import vec, vec_random, density_op, density_op_random, completely_mixed_computational\n",
    "\n",
    "from paddle import matmul, transpose, trace \n",
    "\n",
    "\n",
    "# Set the angle parameter theta = pi\n",
    "theta = np.array([np.pi])\n",
    "    \n",
    "# We need to convert numpy.ndarray to Tensor in PaddlePaddle\n",
    "theta = paddle.to_tensor(theta)\n",
    "\n",
    "# Set the number of qubits required for calculation\n",
    "num_qubits = 1\n",
    "\n",
    "# Initialize our single-bit quantum circuit\n",
    "cir = UAnsatz(num_qubits)\n",
    "\n",
    "# Apply an Rx rotation gate to the first qubit (q0), the angle is pi\n",
    "which_qubit = 0\n",
    "cir.rx(theta, which_qubit)\n",
    "\n",
    "# Convert to numpy.ndarray\n",
    "# Print out this quantum gate\n",
    "print('The matrix representation of quantum gate is:')\n",
    "print(cir.U.numpy())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There is a global phase $-i$ in front between the output and the $X$ (NOT) gate:\n",
    "\n",
    "$$\n",
    "\\text{output} = \\begin{bmatrix} 0 &-i \\\\ -i &0 \\end{bmatrix}\n",
    "= -i\\begin{bmatrix} 0 &1 \\\\ 1 &0 \\end{bmatrix} = -i X.\n",
    "\\tag{17}\n",
    "$$\n",
    "\n",
    "Can you figure out why such a global phase is not important in quantum computing? And not important in what sense?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise: Create a $Y$ gate\n",
    "\n",
    "Similar to the $X$ gate, try to create a $Y$ gate by filling the following code. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-03-09T03:55:00.653853Z",
     "start_time": "2021-03-09T03:55:00.404797Z"
    }
   },
   "outputs": [],
   "source": [
    "theta = \"your code\"\n",
    " \n",
    "theta = paddle.to_tensor(theta)\n",
    "num_qubits = 1\n",
    "cir = UAnsatz(\"your code\")\n",
    "cir.ry(\"your code\")\n",
    "print(cir.U.numpy())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As mentioned before, we have a global phase $-i$ in front:\n",
    "\n",
    "$$\n",
    "\\text{output} = \\begin{bmatrix} 0 &-1 \\\\ 1 &0 \\end{bmatrix}\n",
    "= -i\\begin{bmatrix} 0 &-i \\\\ i &0 \\end{bmatrix} = -i Y.\n",
    "\\tag{18}\n",
    "$$\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Quantum Neural Network\n",
    "\n",
    "After the preparations above, we now have the necessary knowledge to have a taste on quantum machine learning (QML). QML uses quantum circuits to replace classical neural networks to complete machine learning tasks. So we need to prepare a parameterized quantum circuit (PQC), which is also called Quantum neural network (QNN) or Ansatz. The quantum circuit parameters are adjustable (usually these parameters are the angles $\\theta$ of rotation gates). As we have seen in the last section, using angle $\\pi$ to create a $X$ gate is probably the simplest QNN. If we design an appropriate loss function, then certain computational tasks can be transformed into optimization problems. Keep adjusting the parameters in PQC until the loss function convergences. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example: How to create a quantum neural network?\n",
    "\n",
    "QNN can usually be expressed as a combination of single-qubit gates and two-qubit gates. One of the widely used circuit architectures is the hardware-efficient ansatz consists of $\\{R_x, R_y, R_z, \\text{CNOT}_{j,j+1} \\}$. They are easy to implement on near-term devices (usually superconducting qubits) because $\\text{CNOT}_{j,j+1} $ only works on adjacent qubits and hence mitigate the topological connectivity issues. The figure below gives us a concrete example:\n",
    "\n",
    "![intro-fig-gate1](./figures/intro-fig-gate1.png)\n",
    "\n",
    "Each horizontal line here represents a qubit. We define the upper qubit to be the first qubit $q_0$; the lower one is the second qubit $q_1$. From left to right, it represents the order that we apply quantum gates. The leftmost quantum gate will be applied first. Next, let’s take a look on how to build this simple two-qubit quantum neural network on Paddle Quantum."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-04-30T09:20:13.355621Z",
     "start_time": "2021-04-30T09:20:13.331839Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The matrix representation of the quantum neural network U(theta=pi) in the figure is:\n",
      "[[ 0.0000000e+00 -1.0000000e+00  6.1232340e-17 -6.1232340e-17]\n",
      " [-1.0000000e+00  0.0000000e+00 -6.1232340e-17  6.1232340e-17]\n",
      " [-6.1232340e-17  6.1232340e-17  1.0000000e+00  1.2246468e-16]\n",
      " [ 6.1232340e-17 -6.1232340e-17 -1.2246468e-16  1.0000000e+00]]\n"
     ]
    }
   ],
   "source": [
    "# Set the angle parameter theta\n",
    "theta = np.full([4], np.pi)\n",
    "    \n",
    "# We need to convert numpy.ndarray to Tensor in PaddlePaddle\n",
    "theta = paddle.to_tensor(theta)\n",
    "\n",
    "# Initialize the quantum circuit\n",
    "num_qubits = 2\n",
    "cir = UAnsatz(num_qubits)\n",
    "\n",
    "# Add single-qubit rotation gates\n",
    "cir.ry(theta[0], 0)\n",
    "cir.ry(theta[1], 1)\n",
    "\n",
    "# Add two-qubit gate\n",
    "cir.cnot([0, 1])\n",
    "\n",
    "# Add single-qubit rotation gates\n",
    "cir.ry(theta[2], 0)\n",
    "cir.ry(theta[3], 1)\n",
    "\n",
    "print('The matrix representation of the quantum neural network U(theta=pi) in the figure is:')\n",
    "print(cir.U.numpy().real)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$$\n",
    "\\text{output} = \n",
    "\\begin{bmatrix} \n",
    "0  &-1 &0 &0 \\\\ \n",
    "-1 &0  &0 &0 \\\\\n",
    "0  &0  &1 &0 \\\\\n",
    "0  &0  &0 &1 \n",
    "\\end{bmatrix}.\n",
    "\\tag{19}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Exercise\n",
    "\n",
    "Given the following code, can you work out the corresponding circuit?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-04-30T09:20:15.796777Z",
     "start_time": "2021-04-30T09:20:15.786887Z"
    }
   },
   "outputs": [],
   "source": [
    "theta = np.full([6], np.pi)\n",
    "\n",
    "theta = paddle.to_tensor(theta)\n",
    "\n",
    "num_qubits = 3\n",
    "cir = UAnsatz(num_qubits)\n",
    "\n",
    "cir.ry(theta[0], 0)\n",
    "cir.ry(theta[1], 1)\n",
    "cir.ry(theta[2], 2)\n",
    "\n",
    "cir.cnot([0, 1])\n",
    "cir.cnot([1, 2])\n",
    "\n",
    "cir.ry(theta[3], 0)\n",
    "cir.ry(theta[4], 1)\n",
    "cir.ry(theta[5], 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Answer:\n",
    "\n",
    "![intro-fig-gate2](./figures/intro-fig-gate2.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can print your circuit using Paddle Quantum as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-04-30T09:20:18.642677Z",
     "start_time": "2021-04-30T09:20:18.636895Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--Ry(3.142)----*----Ry(3.142)---------------\n",
      "               |                            \n",
      "--Ry(3.142)----X--------*--------Ry(3.142)--\n",
      "                        |                   \n",
      "--Ry(3.142)-------------X--------Ry(3.142)--\n",
      "                                            \n"
     ]
    }
   ],
   "source": [
    "print(cir)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Built-in circuit templates\n",
    "\n",
    "In the latest version of Paddle Quantum, we provide some built-in circuit templates to make users' life easier."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-03-09T03:55:20.402902Z",
     "start_time": "2021-03-09T03:55:19.838729Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "N = 3 # Set the number of qubits\n",
    "       \n",
    "# Initialize the quantum circuit\n",
    "cir = UAnsatz(N)\n",
    "\n",
    "# Apply Hadamard gate on each qubit\n",
    "cir.superposition_layer()\n",
    "\n",
    "# Prepare output state\n",
    "# If the user does not enter the initial quantum state, the default initial is |00..0>\n",
    "final_state = cir.run_state_vector()\n",
    "\n",
    "# Get the theoretical value of the probability distribution, set shots = 0\n",
    "res = cir.measure(shots = 0, plot = True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-03-09T03:55:21.071722Z",
     "start_time": "2021-03-09T03:55:20.413129Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "N = 3 # Set the number of qubits\n",
    "    \n",
    "# Initialize the quantum circuit\n",
    "cir = UAnsatz(N)\n",
    "\n",
    "# Apply Ry(pi/4) rotation gate on each qubit\n",
    "cir.weak_superposition_layer()\n",
    "\n",
    "# Prepare output state\n",
    "# If the user does not enter the initial quantum state, the default initial state is |00..0>\n",
    "final_state = cir.run_state_vector()\n",
    "\n",
    "# Get the theoretical value of the probability distribution, set shots = 0\n",
    "res = cir.measure(shots = 0, plot = True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The following figure depicts a handy circuit template `complex_entangled_layer(theta, DEPTH)` . Users can extend the circuit architecture by changing the circuit depth parameter `DEPTH`. Define generalized rotation gate $U_3$ as\n",
    "\n",
    "$$\n",
    "U_3(\\theta, \\phi, \\varphi) :=\n",
    "\\begin{bmatrix}\n",
    "\\cos \\frac{\\theta}{2} & -e^{i \\varphi}\\sin \\frac{\\theta}{2} \\\\\n",
    "e^{i \\phi}\\sin \\frac{\\theta}{2} &e^{i (\\phi+\\varphi)} \\cos \\frac{\\theta}{2}\n",
    "\\end{bmatrix}.\n",
    "\\tag{20}\n",
    "$$\n",
    "\n",
    "The $U_3$ rotation gate is equivalent to the combination of three different rotation gates:\n",
    "\n",
    "$$\n",
    "U_3(\\theta, \\phi, \\varphi) \n",
    "= R_z(\\phi)*R_y(\\theta)*R_z(\\varphi)\n",
    ":=\n",
    "\\begin{bmatrix}\n",
    "e^{-i\\frac{\\phi}{2}} & 0 \\\\ \n",
    "0 & e^{i\\frac{\\phi}{2}}\n",
    "\\end{bmatrix}\n",
    "\\begin{bmatrix}\n",
    "\\cos \\frac{\\theta}{2} &-\\sin \\frac{\\theta}{2} \\\\ \n",
    "\\sin \\frac{\\theta}{2} &\\cos \\frac{\\theta}{2} \n",
    "\\end{bmatrix}\n",
    "\\begin{bmatrix}\n",
    "e^{-i\\frac{\\varphi}{2}} & 0 \\\\ \n",
    "0 & e^{i\\frac{\\varphi}{2}}\n",
    "\\end{bmatrix}.\n",
    "\\tag{21}\n",
    "$$\n",
    "\n",
    "![intro-fig-complex_entangled_layer2](./figures/intro-fig-complex_entangled_layer2.png)\n",
    "\n",
    "When our task does not involve imaginary numbers, it is more efficient to use the circuit template `real_entangled_layer(theta, DEPTH)` ($R_y$ instead of $U_3$)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-03-09T03:55:24.555510Z",
     "start_time": "2021-03-09T03:55:24.030742Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "N = 4 # Set the number of qubits\n",
    "DEPTH = 6 # Set the quantum circuit depth\n",
    "theta = np.random.randn(DEPTH, N, 3)\n",
    "    \n",
    "# We need to convert numpy.ndarray to Tensor in PaddlePaddle\n",
    "theta = paddle.to_tensor(theta)\n",
    "\n",
    "# Initialize the quantum circuit\n",
    "cir = UAnsatz(N)\n",
    "\n",
    "# Add a complex strong entanglement structure QNN with depth D = 6 {Rz+Ry+Rz/U3 + CNOT's}\n",
    "cir.complex_entangled_layer(theta, DEPTH)\n",
    "\n",
    "# Prepare output state\n",
    "# If the user does not enter the initial quantum state, the default initial is |00..0>\n",
    "final_state = cir.run_state_vector()\n",
    "\n",
    "# Measure the output state [0, 1, 2] qubits 2048 times, and count the frequency of the measurement results\n",
    "res = cir.measure(shots = 2048, which_qubits = [0, 1, 2], plot = True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "# Operating Mode of Paddle Quantum\n",
    "\n",
    "## Wave function vector mode\n",
    "\n",
    "The so-called wave function mode is to use complex vectors to represent and store the quantum states. Vector mode can only handle pure states, but this mode efficiently supports **20+ qubit** operations on personal computer hardware. Users can test the limits of their computers. Under this representation, the essential operation of the quantum gate (unitary matrix) acting on qubits (a complex vector to describe the state) is **multiplying a matrix by a vector**:\n",
    "\n",
    "$$\n",
    "|\\psi\\rangle = U |\\psi_0\\rangle.\n",
    "\\tag{22}\n",
    "$$\n",
    "\n",
    "A function `cir.run_state_vector(input_state = None)` will be used in the following code. If we don't enter any initial quantum state, all qubits will be set into the $\\lvert {0}\\rangle$ state by default. Let's take a specific example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-03-09T03:55:44.714297Z",
     "start_time": "2021-03-09T03:55:28.589382Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1.08337247e-03+0.j  1.00193659e-04+0.j  1.16958435e-03+0.j ...\n",
      "  -6.02439155e-04+0.j  7.83088243e-05+0.j  6.42545561e-05+0.j]]\n"
     ]
    }
   ],
   "source": [
    "N = 20 # Set the number of qubits\n",
    "DEPTH = 6 # Set the quantum circuit depth\n",
    "theta = np.random.randn(DEPTH, N, 1)\n",
    "\n",
    "# Call the built-in |00..0> initial state\n",
    "initial_state1 = vec(N)\n",
    "# Call the built-in random quantum state |psi>\n",
    "initial_state2 = vec_random(N)\n",
    "    \n",
    "# We need to convert numpy.ndarray to Tensor in PaddlePaddle\n",
    "theta = paddle.to_tensor(theta)\n",
    "initial_state = paddle.to_tensor(initial_state1)\n",
    "\n",
    "# Initialize the quantum circuit\n",
    "cir = UAnsatz(N)\n",
    "\n",
    "# Add a real entanglement structure QNN {Ry+CNOT's} with depth of DEPTH\n",
    "cir.real_entangled_layer(theta, DEPTH)\n",
    "\n",
    "# Prepare output state\n",
    "# If the user does not enter the initial quantum state, the default initial state is |00..0>\n",
    "final_state = cir.run_state_vector(initial_state)\n",
    "print(final_state.numpy())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "## Density matrix mode\n",
    "\n",
    "Paddle Quantum also supports the density matrix mode, which is to use density matrices $\\rho = \\sum_i P_i |\\psi_i\\rangle\\langle\\psi_i|$ to represent and store quantum states. This mode can supports **mixed state simulation** . But in density matrix mode, personal computer hardware can only support around 10 qubits. Please pay attention to this limitation. We are constantly optimizing the performance of the simulator in this mode. Under this representation, quantum gates (unitary matrices) acting on the quantum states (Hermitian matrix with a trace of 1) can be viewed as **matrix multiplication**:\n",
    "\n",
    "$$\n",
    "\\rho = U \\rho_0 U^\\dagger.\n",
    "\\tag{23}\n",
    "$$\n",
    "\n",
    "Function `cir.run_density_matrix()` will be used in the following code. Here is an  example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-03-09T03:55:45.027724Z",
     "start_time": "2021-03-09T03:55:44.723567Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 0.86516792+0.j  0.08806816+0.j -0.21659148+0.j  0.2489669 +0.j]\n",
      " [ 0.08806816+0.j  0.00896474+0.j -0.02204753+0.j  0.02534312+0.j]\n",
      " [-0.21659148+0.j -0.02204753+0.j  0.05422285+0.j -0.06232791+0.j]\n",
      " [ 0.2489669 +0.j  0.02534312+0.j -0.06232791+0.j  0.0716445 +0.j]]\n"
     ]
    }
   ],
   "source": [
    "N = 2 # Set the number of qubits\n",
    "DEPTH = 6 # Set the quantum circuit depth\n",
    "theta = np.random.randn(DEPTH, N, 1)\n",
    "\n",
    "# Call the built-in |00..0><00..0| initial state\n",
    "initial_state1 = density_op(N)\n",
    "# Call the built-in random quantum state, you can specify whether to allow complex number elements and matrix rank\n",
    "initial_state2 = density_op_random(N, real_or_complex=2, rank=4)\n",
    "# Call the complete mixed state under the built-in calculation base\n",
    "initial_state3 = completely_mixed_computational(N)\n",
    "\n",
    "# We need to convert numpy.ndarray to Tensor in PaddlePaddle\n",
    "theta = paddle.to_tensor(theta)\n",
    "initial_state = paddle.to_tensor(initial_state1)\n",
    "\n",
    "# Initialize the quantum circuit\n",
    "cir = UAnsatz(N)\n",
    "\n",
    "# Add a real number strong entanglement structure QNN {Ry+CNOT's} with depth of DEPTH\n",
    "cir.real_entangled_layer(theta, DEPTH)\n",
    "\n",
    "# Prepare output state\n",
    "# If the user does not enter the initial quantum state, the default initial is |00..0><00..0|\n",
    "final_state = cir.run_density_matrix(initial_state)\n",
    "print(final_state.numpy())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise: How to prepare Bell states from computational basis\n",
    "\n",
    "Bell state is a widely used quantum entangled state, which can be expressed as\n",
    "\n",
    "$$\n",
    "|\\Phi^+\\rangle = \\frac{1}{\\sqrt{2}} \\big(|00\\rangle + |11\\rangle\\big)\n",
    "= \\frac{1}{\\sqrt{2}} \\,\n",
    "\\begin{bmatrix}\n",
    "1 \\\\\n",
    "0 \\\\\n",
    "0 \\\\\n",
    "1\n",
    "\\end{bmatrix}.\n",
    "\\tag{24}\n",
    "$$\n",
    "\n",
    "So how do we use Paddle Quantum to prepare a Bell state? We can use the following quantum circuit :\n",
    "\n",
    "![intro-fig-bell2](./figures/intro-fig-bell2.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-03-09T03:55:49.403917Z",
     "start_time": "2021-03-09T03:55:48.909563Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The Bell state is:\n",
      " [0.70710678+0.j 0.        +0.j 0.        +0.j 0.70710678+0.j]\n"
     ]
    }
   ],
   "source": [
    "# Initialize the quantum circuit\n",
    "cir = UAnsatz(2)\n",
    "\n",
    "# Add quantum gates\n",
    "cir.h(0)\n",
    "cir.cnot([0, 1])\n",
    "\n",
    "# If the user does not enter the initial quantum state, the default initial is |00..0>\n",
    "output_state = cir.run_state_vector()\n",
    "\n",
    "# We measure the output state 2048 times and obtain the frequency distribution of the measurement results\n",
    "cir.measure(shots = 2048, plot = True)\n",
    "\n",
    "print('The Bell state is:\\n', output_state.numpy())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# PaddlePaddle Optimizer Tutorial\n",
    "\n",
    "## Example: Using gradient descent in PaddlePaddle to optimize multivariable functions\n",
    "\n",
    "\n",
    "In this section, we will learn how to use an optimizer in PaddlePaddle to find the minimum value of a multivariable function, for example,\n",
    "\n",
    "$$\n",
    "\\mathcal{L}(\\theta_1, \\theta_2, \\theta_3)\n",
    "= (\\theta_1)^2 + (\\theta_2)^2 + (\\theta_3)^2 + 10.\n",
    "\\tag{25}\n",
    "$$\n",
    "\n",
    "It is clear when $\\theta_1 = \\theta_2 = \\theta_3 = 0$, $\\mathcal{L}$ takes the minimum value of 10."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-03-09T03:56:01.481603Z",
     "start_time": "2021-03-09T03:56:01.040146Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The minimum value of the loss function is: 10.000000010745854\n"
     ]
    }
   ],
   "source": [
    "# Set hyper parameter\n",
    "theta_size = 3\n",
    "ITR = 200 # Set the number of iterations\n",
    "LR = 0.5  # Set the learning rate\n",
    "SEED = 1  # Fix random number seed\n",
    "paddle.seed(SEED)\n",
    "\n",
    "class Optimization_ex1(paddle.nn.Layer):\n",
    "    \n",
    "    def __init__(self, shape, dtype='float64'):\n",
    "        super(Optimization_ex1, self).__init__()\n",
    "        \n",
    "        # Initialize a list of learnable parameters with length theta_size\n",
    "        # Use the uniform distribution of [-5, 5] to fill the initial value\n",
    "        self.theta = self.create_parameter(shape=shape, \n",
    "                                           default_initializer=paddle.nn.initializer.Uniform(low=-5., high=5.), \n",
    "                                           dtype=dtype, is_bias=False)\n",
    "\n",
    "    # Define loss function and forward propagation mechanism\n",
    "    def forward(self):\n",
    "        loss = self.theta[0] ** 2 + self.theta[1] ** 2 + self.theta[2] ** 2 + 10\n",
    "        return loss\n",
    "    \n",
    "# Record intermediate optimization results\n",
    "loss_list = []\n",
    "parameter_list = []\n",
    "    \n",
    "# Define network dimensions\n",
    "myLayer = Optimization_ex1([theta_size])\n",
    "\n",
    "# Use Adam optimizer to get relatively good convergence\n",
    "# Of course you can change to SGD or RMSprop.\n",
    "opt = paddle.optimizer.Adam(\n",
    "learning_rate = LR, parameters = myLayer.parameters())\n",
    "\n",
    "# Iteration of optimization\n",
    "for itr in range(ITR):\n",
    "\n",
    "    # Forward propagation calculates the loss function\n",
    "    loss = myLayer()[0]\n",
    "\n",
    "    # Backpropagation optimizes the loss function\n",
    "    loss.backward()\n",
    "    opt.minimize(loss)\n",
    "    opt.clear_grad()\n",
    "\n",
    "    # Record the learning process\n",
    "    loss_list.append(loss.numpy()[0])\n",
    "    parameter_list.append(myLayer.parameters()[0].numpy())\n",
    "\n",
    "print('The minimum value of the loss function is:', loss_list[-1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise: Finding Eigenvalues\n",
    "\n",
    "Next, let's try a more complicated loss function. First, we introduce a random Hermitian matrix $H$ whose **eigenvalues** are the diagonal elements of matrix $D$, where\n",
    "\n",
    "$$\n",
    "D = \\begin{bmatrix} 0.2 &0 \\\\ 0 &0.8 \\end{bmatrix}.\n",
    "\\tag{26}\n",
    "$$\n",
    "\n",
    "Don't worry, we will help you generate this Hermitian matrix $H$.\n",
    "\n",
    "Initialize the parameter vector $\\boldsymbol{\\theta}$ to construct a simple linear operation $U(\\boldsymbol{\\theta}) = R_z(\\theta_1)*R_y(\\theta_2)*R_z(\\theta_3)$:\n",
    "\n",
    "$$\n",
    "U(\\theta_1, \\theta_2, \\theta_3) =\n",
    "\\begin{bmatrix}\n",
    "e^{-i\\frac{\\theta_1}{2}} & 0 \\\\\n",
    "0 & e^{i\\frac{\\theta_1}{2}}\n",
    "\\end{bmatrix}\n",
    "\\begin{bmatrix}\n",
    "\\cos \\frac{\\theta_2}{2} &-\\sin \\frac{\\theta_2}{2} \\\\\n",
    "\\sin \\frac{\\theta_2}{2} &\\cos \\frac{\\theta_2}{2}\n",
    "\\end{bmatrix}\n",
    "\\begin{bmatrix}\n",
    "e^{-i\\frac{\\theta_3}{2}} & 0 \\\\\n",
    "0 & e^{i\\frac{\\theta_3}{2}}\n",
    "\\end{bmatrix}.\n",
    "\\tag{27}\n",
    "$$\n",
    "\n",
    "Multiply this matrix (ansatz) by $|0\\rangle$ to get a new 2-dimensional complex vector\n",
    "\n",
    "$$\n",
    "|\\phi\\rangle = U(\\theta_1, \\theta_2, \\theta_3)|0\\rangle.\n",
    "\\tag{28}\n",
    "$$\n",
    "\n",
    "Then, we define the loss function as\n",
    "\n",
    "$$\n",
    "\\mathcal{L}(\\theta_1, \\theta_2, \\theta_3)\n",
    "= \\langle\\phi| H |\\phi\\rangle\n",
    "= \\langle0| U^{\\dagger}H U |0\\rangle.\n",
    "\\tag{29}\n",
    "$$\n",
    "\n",
    "Let's see what we got after optimization!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-03-09T03:56:04.176637Z",
     "start_time": "2021-03-09T03:56:03.680838Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The randomly generated matrix H according to the spectral decomposition is:\n",
      "[[ 0.26680964+0.j         -0.06472222-0.17729436j]\n",
      " [-0.06472222+0.17729436j  0.73319036+0.j        ]] \n",
      "\n",
      "The eigenvalues of H are:\n",
      "[0.2 0.8]\n"
     ]
    }
   ],
   "source": [
    "from scipy.stats import unitary_group\n",
    "\n",
    "# V is a 2x2 random unitary matrix\n",
    "V = unitary_group.rvs(2)\n",
    "\n",
    "# The diagonal elements in D are the eigenvalue of H\n",
    "# You can change the diagonal element value here\n",
    "D = np.diag([0.2, 0.8])\n",
    "\n",
    "# V_dagger is the Hermitian transpose of V\n",
    "V_dagger = V.conj().T\n",
    "\n",
    "# @: Represents matrix multiplication\n",
    "H = (V @ D @ V_dagger)\n",
    "print('The randomly generated matrix H according to the spectral decomposition is:')\n",
    "print(H,'\\n')\n",
    "print('The eigenvalues of H are:')\n",
    "print(np.linalg.eigh(H)[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-03-09T03:56:04.205868Z",
     "start_time": "2021-03-09T03:56:04.186818Z"
    }
   },
   "outputs": [],
   "source": [
    "# Hyper parameter settings\n",
    "theta_size = 3 # set theta dimension\n",
    "num_qubits = 1 # Set the number of qubits\n",
    "ITR = 50 # Set the number of iterations\n",
    "LR = 0.5 # Set the learning rate\n",
    "SEED = 1 # Fix random seed for initializing theta parameter\n",
    "paddle.seed(SEED)\n",
    "\n",
    "# Set the circuit module separately\n",
    "def U_theta(theta):\n",
    "    \n",
    "    # Initialize the circuit and add the quantum gates\n",
    "    cir = UAnsatz(num_qubits)\n",
    "    cir.rz(theta[0], 0)\n",
    "    cir.ry(theta[1], 0)\n",
    "    cir.rz(theta[2], 0)\n",
    "    \n",
    "    # Return parameterized matrix\n",
    "    return cir.U"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-03-09T03:56:04.793520Z",
     "start_time": "2021-03-09T03:56:04.781463Z"
    }
   },
   "outputs": [],
   "source": [
    "class Optimization_ex2(paddle.nn.Layer):\n",
    "    \n",
    "    def __init__(self, shape, dtype='float64'):\n",
    "        super(Optimization_ex2, self).__init__()\n",
    "        \n",
    "        # Initialize a list of trainable parameters with length theta_size\n",
    "        # And use the uniform distribution of [0, 2*pi] to fill the initial value\n",
    "        self.theta = self.create_parameter(shape=shape, \n",
    "                                           default_initializer=paddle.nn.initializer.Uniform(low=0., high=2*np.pi), \n",
    "                                           dtype=dtype, is_bias=False)\n",
    "        self.H = paddle.to_tensor(H)\n",
    "        \n",
    "    # Define loss function and forward propagation mechanism\n",
    "    def forward(self):\n",
    "        \n",
    "        # Get the unitary matrix representation of the quantum neural network\n",
    "        U = U_theta(self.theta)\n",
    "        \n",
    "        # Conjugate transpose operation\n",
    "        U_dagger = dagger(U)\n",
    "        \n",
    "        # Calculate the loss function\n",
    "        loss = paddle.real(matmul(U_dagger, matmul(self.H, U)))[0][0]\n",
    "        \n",
    "        return loss"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-03-09T03:56:11.561432Z",
     "start_time": "2021-03-09T03:56:10.716719Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "iter: 0 loss: 0.6071\n",
      "iter: 5 loss: 0.4024\n",
      "iter: 10 loss: 0.2953\n",
      "iter: 15 loss: 0.2710\n",
      "iter: 20 loss: 0.2666\n",
      "iter: 25 loss: 0.2654\n",
      "iter: 30 loss: 0.2643\n",
      "iter: 35 loss: 0.2627\n",
      "iter: 40 loss: 0.2601\n",
      "iter: 45 loss: 0.2563\n",
      "The minimum value of the loss function is: 0.25196530073166423\n"
     ]
    }
   ],
   "source": [
    "loss_list = []\n",
    "parameter_list = []\n",
    "\n",
    "myLayer = Optimization_ex2([theta_size])\n",
    "\n",
    "# SGD optimizer\n",
    "opt = paddle.optimizer.SGD(learning_rate = LR, parameters = myLayer.parameters())\n",
    "\n",
    "# Optimization cycle\n",
    "for itr in range(ITR):\n",
    "\n",
    "    # Forward propagation calculates loss function\n",
    "    loss = myLayer()[0]\n",
    "\n",
    "    # Back propagation minimizes the loss function\n",
    "    loss.backward()\n",
    "    opt.minimize(loss)\n",
    "    opt.clear_grad()\n",
    "\n",
    "    # Record the learning curve\n",
    "    loss_list.append(loss.numpy()[0])\n",
    "    parameter_list.append(myLayer.parameters()[0].numpy())\n",
    "    if itr % 5 == 0:\n",
    "        print('iter:', itr, 'loss: %.4f'% loss.numpy())\n",
    "\n",
    "print('The minimum value of the loss function is:', loss_list[-1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can change the eigenvalues of $H$. If the diagonal matrix after diagonalization is changed to\n",
    "\n",
    "$$\n",
    "D = \\begin{bmatrix} 0.8 &0 \\\\ 0 &1.2 \\end{bmatrix}.\n",
    "\\tag{30}\n",
    "$$\n",
    "\n",
    "We still get the minimum eigenvalue of $\\lambda_{\\text{min}}(H)=0.8$. Can you find the reason behind it? Or is there any theory behind this?\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Quantum Machine Learning Case Study\n",
    "\n",
    "## Variational Quantum Eigensolver - Unsupervised Learning\n",
    "\n",
    "At this stage, large-scale fault-tolerant quantum computers are still far from us. We can only build noisy intermediate-scale quantum (NISQ) computing devices. A promising type of algorithm suitable for NISQ devices is the quantum-classical hybrid algorithm, or variational quantum algorithms. People expect that this approach could surpass the performance of classical computers in certain applications. Among which, the Variational Quantum Eigensolver (VQE) is such an important application. It uses a parameterized circuit to search the vast Hilbert space and uses the gradient descent or other classical optimization methods to find the optimal parameters, which yield a state that is close to the ground state of a given Hamiltonian (find the minimum eigenvalue of a Hermitian matrix). Let's go through the following two-qubit example.\n",
    "\n",
    "Suppose we want to find the ground state of the following Hamiltonian:\n",
    "\n",
    "$$\n",
    "H = 0.4 \\, Z \\otimes I + 0.4 \\, I \\otimes Z + 0.2 \\, X \\otimes X.\n",
    "\\tag{31}\n",
    "$$\n",
    "\n",
    "Given the following quantum neural network architecture\n",
    "\n",
    "![intro-fig-vqeAnsatz](./figures/intro-fig-vqeAnsatz.png)\n",
    "\n",
    "We have learned how to build this circuit. If you forget, please go to section **Quantum Neural Network**."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-03-09T03:56:15.148775Z",
     "start_time": "2021-03-09T03:56:15.092238Z"
    }
   },
   "outputs": [],
   "source": [
    "# First generate the Hamiltonian under Pauli string representation\n",
    "# H_info is equivalent to 0.4*kron(I, Z) + 0.4*kron(Z, I) + 0.2*kron(X, X)\n",
    "# Among them, X, Y, Z are the Pauli matrix and I is the identity matrix\n",
    "H_info = [[0.4,'z0'], [0.4,'z1'], [0.2,'x0,x1']]\n",
    "\n",
    "# Set hyper parameter\n",
    "num_qubits = 2\n",
    "theta_size = 4\n",
    "ITR = 60\n",
    "LR = 0.4\n",
    "SEED = 999\n",
    "paddle.seed(SEED)\n",
    "\n",
    "# Convert the Hamiltonian into matrix representation\n",
    "H_matrix = pauli_str_to_matrix(H_info, num_qubits)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-03-09T03:56:15.789743Z",
     "start_time": "2021-03-09T03:56:15.776313Z"
    }
   },
   "outputs": [],
   "source": [
    "class vqe_demo(paddle.nn.Layer):\n",
    "    \n",
    "    def __init__(self, shape, dtype='float64'):\n",
    "        super(vqe_demo, self).__init__()\n",
    "        \n",
    "        # Initialize a list of learnable parameters with length theta_size\n",
    "        # Use the uniform distribution of [0, 2*pi] to fill the initial value\n",
    "        self.theta = self.create_parameter(shape=shape, \n",
    "                                           default_initializer=paddle.nn.initializer.Uniform(low=0., high=2*np.pi), \n",
    "                                           dtype=dtype, is_bias=False)\n",
    "        \n",
    "    # Define loss function and forward propagation mechanism\n",
    "    def forward(self):\n",
    "        \n",
    "        # Initial quantum circuit\n",
    "        cir = UAnsatz(num_qubits)\n",
    "        \n",
    "        # Add quantum gates\n",
    "        cir.ry(self.theta[0], 0)\n",
    "        cir.ry(self.theta[1], 1)\n",
    "        cir.cnot([0, 1])\n",
    "        cir.ry(self.theta[2], 0)\n",
    "        cir.ry(self.theta[3], 1)\n",
    "        \n",
    "        # Choose state vector operation mode\n",
    "        cir.run_state_vector()\n",
    "        \n",
    "        # Calculate the expected value of H_info in the current quantum state\n",
    "        # The formula is given by <psi|H|psi>\n",
    "        loss = cir.expecval(H_info)\n",
    "        \n",
    "        return loss"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-03-09T03:56:27.823274Z",
     "start_time": "2021-03-09T03:56:20.363130Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "iter: 0 loss: -0.2202\n",
      "iter: 10 loss: -0.7239\n",
      "iter: 20 loss: -0.8156\n",
      "iter: 30 loss: -0.8172\n",
      "iter: 40 loss: -0.8205\n",
      "iter: 50 loss: -0.8241\n",
      "The calculated ground state energy is: -0.8243637430772154\n",
      "The real ground state energy is: -0.8246211251235321\n"
     ]
    }
   ],
   "source": [
    "loss_list = []\n",
    "parameter_list = []\n",
    "\n",
    "# Define network dimensions\n",
    "vqe = vqe_demo([theta_size])\n",
    "\n",
    "# We usually use Adam optimizer to get relatively good convergence\n",
    "# Of course you can change it to SGD, Adagrad, or RMS prop as we did here.\n",
    "opt = paddle.optimizer.Adam(\n",
    "  learning_rate = LR, parameters = vqe.parameters())\n",
    "\n",
    "# Optimization cycle\n",
    "for itr in range(ITR):\n",
    "\n",
    "    # Forward propagation calculates loss function\n",
    "    loss = vqe()\n",
    "\n",
    "    # Back propagation minimizes the loss function\n",
    "    loss.backward()\n",
    "    opt.minimize(loss)\n",
    "    opt.clear_grad()\n",
    "\n",
    "    # Record the learning curve\n",
    "    loss_list.append(loss.numpy()[0])\n",
    "    parameter_list.append(vqe.parameters()[0].numpy())\n",
    "    if itr % 10 == 0:\n",
    "        print('iter:', itr, 'loss: %.4f'% loss.numpy())\n",
    "\n",
    "\n",
    "print('The calculated ground state energy is:', loss_list[-1])\n",
    "print('The real ground state energy is:', np.linalg.eigh(H_matrix)[0][0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "_______\n",
    "\n",
    "## References\n",
    "\n",
    "[1] Nielsen, M. A. & Chuang, I. L. Quantum computation and quantum information. (Cambridge university press, 2010).\n",
    "\n",
    "[2] Phillip Kaye, Laflamme, R. & Mosca, M. An Introduction to Quantum Computing. (2007).\n",
    "\n",
    "[3] Biamonte, J. et al. Quantum machine learning. [Nature 549, 195–202 (2017).](https://www.nature.com/articles/nature23474)\n",
    "\n",
    "[4] Schuld, M., Sinayskiy, I. & Petruccione, F. An introduction to quantum machine learning. [Contemp. Phys. 56, 172–185 (2015).](https://www.tandfonline.com/doi/abs/10.1080/00107514.2014.964942)\n",
    "\n",
    "[5] Benedetti, M., Lloyd, E., Sack, S. & Fiorentini, M. Parameterized quantum circuits as machine learning models. [Quantum Sci. Technol. 4, 043001 (2019).](https://iopscience.iop.org/article/10.1088/2058-9565/ab4eb5)\n",
    "\n",
    "[6] [Peruzzo, A. et al. A variational eigenvalue solver on a photonic quantum processor. Nat. Commun. 5, 4213 (2014).](https://www.nature.com/articles/ncomms5213)\n",
    "\n",
    "[7] [McClean, J. R., Romero, J., Babbush, R. & Aspuru-Guzik, A. The theory of variational hybrid quantum-classical algorithms. New J. Phys. 18, 023023 (2016).](https://iopscience.iop.org/article/10.1088/1367-2630/18/2/023023)\n",
    "\n",
    "[8] [Kandala, A. et al. Hardware-efficient variational quantum eigensolver for small molecules and quantum magnets. Nature 549, 242–246 (2017).](https://www.nature.com/articles/nature23879)\n",
    "\n",
    "[9] [Mitarai, K., Negoro, M., Kitagawa, M. & Fujii, K. Quantum circuit learning. Phys. Rev. A 98, 032309 (2018).](https://journals.aps.org/pra/abstract/10.1103/PhysRevA.98.032309)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.10"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "580px"
   },
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
